package com.ethan.protostuff;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.runtime.RuntimeEnv;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import org.springframework.objenesis.Objenesis;
import org.springframework.objenesis.ObjenesisStd;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author ethan
 * create 2018-06-13 下午2:22
 * desc
 **/
public class SerializationUtil2 {
    private static Map<Class<?>,RuntimeSchema<?>> cachedSchema = new ConcurrentHashMap<>();
    private static Objenesis objenesis = new ObjenesisStd(true);


    @SuppressWarnings({"unchecked","unused"})
    private static <T> RuntimeSchema<T> getSchema(Class<T> tClass,String[] exclusions){
        RuntimeSchema<T> schema = (RuntimeSchema<T>) cachedSchema.get(tClass);
        if(schema == null){
            if (exclusions == null || exclusions.length == 0) {
                schema = RuntimeSchema.createFrom(tClass);
            } else {
                schema = RuntimeSchema.createFrom(tClass, exclusions, RuntimeEnv.ID_STRATEGY);
            }
            cachedSchema.put(tClass,schema);
        }
        return schema;
    }

    @SuppressWarnings({"unchecked","unused"})
    public static <T> byte[] serialize(T obj,String[] exclusions){
        Class<T> tClass = (Class<T>) obj.getClass();
        LinkedBuffer linkedBuffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try {
            RuntimeSchema<T> schema = getSchema(tClass,exclusions);
            return ProtostuffIOUtil.toByteArray(obj,schema,linkedBuffer);
        }catch (Exception e){
            throw new IllegalStateException(e.getMessage(),e);
        }finally {
            linkedBuffer.clear();
        }
    }


    public static <T> T deserialize(byte[] data,Class<T> tClass,String[] exclusions){
        try {
            RuntimeSchema<T> schema = getSchema(tClass,exclusions);
            T message = (T) objenesis.newInstance(tClass);
            ProtostuffIOUtil.mergeFrom(data,message,schema);
            return message;
        }catch (Exception e){
            throw new IllegalStateException(e.getMessage(),e);
        }
    }

    public static <T> byte[] serialize(T obj){
        return serialize(obj,null);
    }

    public static <T> T deserialize(byte[] data,Class<T> tClass){
        return deserialize(data,tClass,null);
    }

}
